Архитектура ОС

Процессы и потоки (нити)

Архитектура ОС

План лекции

1. Понятие процесса и потока

2. Модели процессов и потоков

3. Реализация потоков в ядре и в пространстве пользователя

4. Взаимодействие процессов (IPC)

5. Межпроцессное взаимодействие: каналы, очереди сообщений, разделяемая память

6. Практические примеры

Процессы и потоки (нити)
Архитектура ОС

1. Понятие процесса

Процесс — экземпляр программы во время выполнения.

Компоненты процесса:

  • Исполняемый код (текстовый сегмент)
  • Данные (глобальные переменные, куча)
  • Стек вызовов функций
  • Содержимое регистров процессора
  • Открытые файлы и другие ресурсы ОС
Процессы и потоки (нити)
Архитектура ОС

Что содержит PCB (Process Control Block)

  • Идентификатор процесса (PID)

  • Состояние процесса

  • Счётчик команд (PC)

  • Регистры процессора

  • Указатели на стек

  • Информация о планировании (приоритет)

  • Управление памятью

  • Учёт использования ресурсов

  • Информация об I/O

  • Список открытых файлов

Процессы и потоки (нити)
Архитектура ОС

Понятие потока (нити)

Поток (Thread) — наименьшая единица выполнения внутри процесса.

  • Потоки одного процесса разделяют адресное пространство
  • Каждый поток имеет свой собственный:
    • Стек
    • Счётчик команд (PC)
    • Набор регистров
  • Потоки обеспечивают параллелизм внутри одного процесса
Процессы и потоки (нити)
Архитектура ОС

Процесс vs Поток

Характеристика Процесс Поток
Адресное пространство Изолированное Общее (внутри процесса)
Создание Дорого (fork) Дёшево (pthread_create)
Переключение контекста Медленное Быстрое
Обмен данными Через IPC Через общую память
Отказ одного Не влияет на другие Может «убить» весь процесс
Процессы и потоки (нити)
Архитектура ОС

2. Однопоточный и многопоточный процесс

Однопоточный процесс:

  • Один поток выполнения
  • Последовательное выполнение инструкций

Многопоточный процесс:

  • Несколько потоков внутри одного процесса
  • Параллельное выполнение задач
  • Разделение ресурсов между потоками
  • Примеры: веб-сервер, браузер, IDE
Процессы и потоки (нити)
Архитектура ОС

Визуализация многопоточного процесса

Разделяют потоки:

  • Адресное пространство
  • Глобальные переменные
  • Открытые файлы
  • Сигналы

Собственные для каждого потока:

  • Стек
  • Счётчик команд
  • Регистры
  • Состояние (ready, running, blocked)
Процессы и потоки (нити)
Архитектура ОС

3. Модели отображения потоков

Три основные модели:

  1. Многие к одному — несколько пользовательских потоков → один поток ядра
  2. Один к одному — каждый пользовательский поток → свой поток ядра
  3. Многие ко многимnn пользовательских потоков → mm потоков ядра (mnm \le n)

Выбор модели влияет на производительность и переносимость.

Процессы и потоки (нити)
Архитектура ОС

Модель «Многие к одному»

  • Все потоки пользователя отображаются на один поток ядра
  • Переключение потоков — быстрое (в пользовательском пространстве)
  • Блокировка одного потока → блокирует весь процесс
  • ОС не знает о существовании потоков
  • Пример: ранние реализации POSIX threads (GNU Portable Threads)
Процессы и потоки (нити)
Архитектура ОС

Модель «Один к одному»

  • Каждый пользовательский поток → отдельный поток ядра
  • Истинный параллелизм на нескольких процессорах
  • Блокировка одного потока не блокирует другие
  • Большее потребление ресурсов
  • Ограничение на число потоков
  • Примеры: Windows, Linux (NPTL)
Процессы и потоки (нити)
Архитектура ОС

Модель «Многие ко многим»

  • nn пользовательских потоков отображаются на mm потоков ядра (mnm \le n)
  • Гибкость: ядро может создавать столько потоков, сколько нужно
  • Комбинирует преимущества двух предыдущих моделей
  • Сложнее в реализации
  • Вариант: двухуровневая модель (многие ко многим + один к одному)
  • Пример: Solaris (до версии 9)
Процессы и потоки (нити)
Архитектура ОС

Сравнение моделей потоков

Критерий Многие к одному Один к одному Многие ко многим
Параллелизм Нет Да Ограниченный
Переключение Очень быстрое Медленнее Среднее
Блокировка Весь процесс Только поток Только поток
Сложность Низкая Средняя Высокая
Процессы и потоки (нити)
Архитектура ОС

Преимущества многопоточности

  • Отзывчивость — интерфейс не «зависает» при длительных операциях
  • Разделение ресурсов — потоки естественно разделяют память
  • Экономичность — создание потока дешевле создания процесса
  • Масштабируемость — использование многоядерных процессоров
  • Быстрое переключение — меньше накладных расходов
Процессы и потоки (нити)
Архитектура ОС

Потоки POSIX (pthread)

Стандарт POSIX Threads (pthread) — API для работы с потоками:

  • pthread_create() — создание потока
  • pthread_join() — ожидание завершения потока
  • pthread_exit() — завершение потока
  • pthread_mutex_lock/unlock() — взаимное исключение
  • pthread_cond_wait/signal() — условные переменные
Процессы и потоки (нити)
Архитектура ОС

4. Реализация потоков в пространстве пользователя

Потоки уровня пользователя (user-level threads):

  • Библиотека управляет потоками (ядро «не видит» их)
  • Переключение — очень быстрое (нет системного вызова)
  • Не требуется поддержка от ядра ОС
  • Проблема: блокировка одного потока → блокирует весь процесс
  • Планирование — кооперативное или вытеснительное внутри библиотеки
Процессы и потоки (нити)
Архитектура ОС

Проблемы потоков уровня пользователя

  • Системный вызов блокирует все потоки процесса
  • Ядро не может передать квант времени другому потоку
  • Невозможно использовать несколько процессоров
  • Сложно реализовать read() без блокировки
  • Решение: обёртки (wrappers) для системных вызовов или неблокирующий I/O
Процессы и потоки (нити)
Архитектура ОС

Потоки уровня ядра (kernel-level threads)

Потоки ядра:

  • Управляются непосредственно ядром ОС
  • Ядро знает о каждом потоке и планирует его
  • Параллельное выполнение на нескольких процессорах
  • Блокировка одного потока — другие продолжают работу
  • Недостаток: большее время переключения (системный вызов)
  • Примеры: Windows threads, Linux pthreads (NPTL)
Процессы и потоки (нити)
Архитектура ОС

Сравнение пользовательских и ядерных потоков

Пользовательские:

  • Быстрое переключение
  • Ядро не участвует
  • Блокировка всего процесса
  • Нет параллелизма
  • Переносимы

Ядерные:

  • Медленнее переключение
  • Ядро управляет
  • Блокировка одного потока
  • Истинный параллелизм
  • Зависят от ОС
Процессы и потоки (нити)
Архитектура ОС

Гибридные модели

  • Комбинация потоков пользователя и ядра
  • Ядро предоставляет несколько kk-потоков
  • Библиотека распределяет uu-потоки по kk-потокам (u>ku > k)
  • Баланс между производительностью и параллелизмом
  • Пример: NetBSD saffinity, старые версии Solaris
Процессы и потоки (нити)
Архитектура ОС

Системный вызов Linux: clone()

В Linux и процессы, и потоки создаются через clone():

  • fork() — полное копирование адресного пространства
  • clone()выборочное разделение ресурсов:
    • CLONE_VM — разделить память (→ поток)
    • CLONE_FS — разделить информацию о файловой системе
    • CLONE_FILES — разделить таблицу файловых дескрипторов
    • CLONE_SIGHAND — разделить обработчики сигналов
Процессы и потоки (нити)
Архитектура ОС

fork() vs clone()

fork()

  • Полная копия процесса
  • Новое адресное пространство (COW)
  • Новая таблица файлов
  • PID дочернего процесса
  • Дорого по ресурсам

clone()

  • Гибкое управление разделением
  • Может разделить память, файлы, сигналы
  • Тот же PID (с точки зрения пользователя — tid)
  • Используется для создания потоков
  • Легковесно
Процессы и потоки (нити)
Архитектура ОС

Задачи в Linux (Tasks)

  • В Linux нет отдельного понятия «поток» и «процесс»
  • Всё — задачи (tasks), описываемые task_struct
  • Потоки — задачи с общным адресным пространством
  • Каждый поток имеет свой tid (Thread ID)
  • getpid() у всех потоков возвращает один PID
  • gettid() возвращает уникальный идентификатор потока
Процессы и потоки (нити)
Архитектура ОС

5. Взаимодействие процессов (IPC)

IPC — Inter-Process Communication

Зачем нужно взаимодействие процессов?

  • Передача данных между процессами
  • Синхронизация доступа к ресурсам
  • Координация выполнения

Две основные модели:

  • Разделяемая память — быстрая, но требует синхронизации
  • Передача сообщений — безопаснее, но медленнее
Процессы и потоки (нити)
Архитектура ОС

Классификация механизмов IPC

Передача данных:

  • Каналы (pipes)
  • Очереди сообщений
  • Сокеты
  • Сигналы

Разделяемые ресурсы:

  • Разделяемая память
  • Семафоры
  • Файлы, отображаемые в память (mmap)
Процессы и потоки (нити)
Архитектура ОС

Синхронизация vs Коммуникация

  • Коммуникация — обмен данными между процессами
  • Синхронизация — координация порядка выполнения
  • Некоторые механизмы обеспечивают и то, и другое
  • Пример: семафор — синхронизация, канал — коммуникация + синхронизация
Процессы и потоки (нити)
Архитектура ОС

IPC: System V и POSIX

System V IPC

  • msgget, msgsnd, msgrcv
  • shmget, shmat, shmdt
  • semget, semop
  • Ключи IPC (ftok)
  • ipcs / ipcrm

POSIX IPC

  • mq_open, mq_send, mq_receive
  • shm_open, mmap
  • sem_open, sem_wait, sem_post
  • Имена в файловой системе
  • Проще в использовании
Процессы и потоки (нити)
Архитектура ОС

6. Каналы (Pipes)

Неименованный канал (anonymous pipe):

  • Однонаправленный поток байтов
  • Создаётся pipe(fd[2])
  • fd[0] — чтение, fd[1] — запись
  • Работает только между родственными процессами (fork)
  • После fork() — родитель пишет, дочерний читает (или наоборот)
Процессы и потоки (нити)
Архитектура ОС

Пример: неименованный канал

#include <unistd.h>
#include <string.h>
#include <stdio.h>

int main() {
    int fd[2];
    pid_t pid;
    char buf[128];

    pipe(fd);
    pid = fork();

    if (pid == 0) {
        close(fd[1]);
        read(fd[0], buf, sizeof(buf));
        printf("Child got: %s\n", buf);
        close(fd[0]);
    } else {
        close(fd[0]);
        write(fd[1], "Hello", 6);
        close(fd[1]);
    }
    return 0;
}
Процессы и потоки (нити)
Архитектура ОС

Именованные каналы (FIFO)

  • Имя в файловой системе (mkfifo())
  • Могут взаимодействовать любые процессы (не только родственные)
  • Двунаправленное взаимодействие (через два FIFO)
  • Персистентны — существуют до удаления (unlink)
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "Hello", 6);
close(fd);
Процессы и потоки (нити)
Архитектура ОС

Очереди сообщений

  • Структурированные сообщения (тип + данные)
  • Процесс может читать сообщения определённого типа
  • Асинхронная передача — отправитель не ждёт получателя
  • Сообщения сохраняются до чтения

System V: msgget(), msgsnd(), msgrcv()
POSIX: mq_open(), mq_send(), mq_receive()

Процессы и потоки (нити)
Архитектура ОС

Разделяемая память

Самый быстрый механизм IPC — прямое отображение памяти в адресные пространства нескольких процессов.

  • Нет копирования данных (в отличие от каналов и сообщений)
  • Процессы работают с одним и тем же участком памяти
  • Требует синхронизации (гонки данных!)
  • shmget() — создание сегмента (System V)
  • shmat() — подключение сегмента к адресному пространству
Процессы и потоки (нити)
Архитектура ОС

Пример: разделяемая память (System V)

#include <sys/shm.h>
#include <string.h>
#include <stdio.h>

int main() {
    int shmid = shmget(1234, 1024, IPC_CREAT | 0666);
    char *shm = (char *)shmat(shmid, NULL, 0);

    strcpy(shm, "Hello from shared memory!");
    printf("Data: %s\n", shm);

    shmdt(shm);
    return 0;
}
Процессы и потоки (нити)
Архитектура ОС

mmap — отображение файла в память

#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

int main() {
    int fd = open("/tmp/mmfile", O_RDWR | O_CREAT, 0666);
    ftruncate(fd, 4096);
    char *p = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                   MAP_SHARED, fd, 0);
    strcpy(p, "Hello via mmap!");
    printf("%s\n", p);
    munmap(p, 4096);
    close(fd);
    return 0;
}
Процессы и потоки (нити)
Архитектура ОС

Семафоры

  • Примитив синхронизации доступа к разделяемым ресурсам
  • Счётчик с атомарными операциями:
    • wait() (P) — уменьшить; если <0< 0 — заблокировать
    • signal() (V) — увеличить; разбудить ожидающий процесс
  • System V: semget(), semop()
  • POSIX: sem_open(), sem_wait(), sem_post()
  • Подробно — в лекции 07 (Синхронизация)
Процессы и потоки (нити)
Архитектура ОС

Сигналы

  • Асинхронные уведомления процессов
  • Посылаются ядром или другим процессом
  • Стандартные сигналы: SIGINT, SIGTERM, SIGKILL, SIGSEGV
  • Обработчик сигнала: signal() или sigaction()
  • Можно использовать для простой IPC (SIGUSR1, SIGUSR2)
  • Ограничение: минимальная передача данных (только факт сигнала)
Процессы и потоки (нити)
Архитектура ОС

Сокеты

  • Двунаправленный канал связи
  • Работают как локально, так и по сети
  • Типы: SOCK_STREAM (TCP), SOCK_DGRAM (UDP)
  • Unix domain sockets — для локальной IPC
  • Универсальный, но более медленный механизм
Процессы и потоки (нити)
Архитектура ОС

Пример: создание потоков (pthread)

#include <pthread.h>
#include <stdio.h>

void *worker(void *arg) {
    long id = (long)arg;
    printf("Thread %ld running\n", id);
    return NULL;
}

int main() {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, worker, (void *)1);
    pthread_create(&t2, NULL, worker, (void *)2);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    return 0;
}
Процессы и потоки (нити)
Архитектура ОС

Паттерн Producer-Consumer

  • Классический паттерн многопоточного программирования
  • Producer — генерирует данные, помещает в буфер
  • Consumer — извлекает данные из буфера и обрабатывает
  • Требует синхронизации доступа к буферу
  • Реализация: мьютекс + условная переменная (или семафоры)
Процессы и потоки (нити)
Архитектура ОС

Паттерн Thread Pool

  • Заранее создаётся пул (NN) рабочих потоков
  • Задачи поступают в очередь
  • Свободный поток берёт задачу из очереди
  • Преимущества:
    • Ограниченное число потоков
    • Нет накладных расходов на создание/уничтожение
    • Предсказуемая нагрузка на систему
Процессы и потоки (нити)
Архитектура ОС

Паттерн Fork-Join

  • Fork — разделение задачи на подзадачи (создание потоков)
  • Параллельное выполнение подзадач
  • Join — ожидание завершения всех потоков, сбор результатов
  • Пример: параллельная обработка элементов массива
main thread
   |
   +-- fork --> thread 1 --> join --+
   +-- fork --> thread 2 --> join --+--> continue
   +-- fork --> thread 3 --> join --+
Процессы и потоки (нити)
Архитектура ОС

Сводная таблица механизмов IPC

Механизм Направление Скорость Синхронизация
Pipe Однонаправленный Средняя Встроенная
FIFO Однонаправленный Средняя Встроенная
Очередь сообщений Двунаправленный Средняя Встроенная
Разделяемая память Двунаправленный Высокая Требуется
Сокет Двунаправленный Низкая Встроенная
Сигнал Однонаправленный
Процессы и потоки (нити)
Архитектура ОС

Заключение

Процессы и потоки (нити)
Архитектура ОС

Ключевые выводы лекции

  • Поток — легковесная единица выполнения внутри процесса

  • Потоки разделяют адресное пространство, но имеют свои стеки

  • Модель «один к одному» — стандарт для Linux и Windows

  • clone() — единый механизм создания процессов и потоков в Linux

  • IPC — фундамент для взаимодействия процессов

  • Разделяемая память — самый быстрый, но требует синхронизации

  • Каналы и сообщения — безопаснее, но медленнее

  • Выбор механизма IPC зависит от задачи

Процессы и потоки (нити)
Архитектура ОС

Вопросы для самоконтроля

  1. Чем отличается процесс от потока?
  2. Какие ресурсы разделяют потоки одного процесса?
  3. Какие существуют модели отображения потоков пользователя на потоки ядра?
  4. В чём преимущества и недостатки потоков уровня пользователя?
  5. В чём преимущества и недостатки потоков уровня ядра?
  6. Как реализованы потоки в Linux (clone)?
  7. Перечислите основные механизмы межпроцессного взаимодействия.
  8. В чём разница между именованными и неименованными каналами?
  9. Какие преимущества даёт разделяемая память по сравнению с другими механизмами IPC?
  10. Что такое pthread и какие основные функции она предоставляет?
Процессы и потоки (нити)
Архитектура ОС

Рекомендуемые ресурсы

Основная литература:

  1. Таненбаум Э., Бос Х. Современные операционные системы. 4-е изд. — Питер, 2015.
  2. Столлингс В. Операционные системы. 9-е изд. — Вильямс, 2018.

Дополнительная литература:

  1. Стивенс У. UNIX. Взаимодействие процессов. — Питер, 2003.
  2. Kerrisk M. The Linux Programming Interface. — No Starch Press, 2010.
Процессы и потоки (нити)

Представляем структуру лекции — от базовых понятий процесса и потока к механизмам межпроцессного взаимодействия. Обратите внимание аудитории на практическую часть в конце.

Процесс — это не программа. Программа — файл на диске, процесс — её живой экземпляр с ресурсами. Аналогия: программа — рецепт, процесс — процесс готовки.

PCB — «паспорт» процесса для ядра. Без него ядро не может управлять процессом: планировать, приостанавливать, возобновлять. PCB хранится в памяти ядра.

Поток — «мини-процесс» внутри процесса. Ключевой момент: потоки разделяют память, что делает обмен данныся быстрым, но создаёт проблемы синхронизации.

Эта таблица — шпаргалка для экзамена. Акцент: сбой потока может «убить» весь процесс — ключевое отличие от изолированности процессов.

Приведите примеры: браузер использует потоки для вкладок, IDE — для компиляции и автодополнения. Однопоточный процесс — классическая программа из курса программирования.

Левая колонка — то, что потоки делят (и из-за чего возможны гонки данных). Правая — что у каждого потока своё (и что нужно сохранять при переключении контекста).

Переходим к архитектурным моделям. Три модели — каждая со своими компромиссами. Это фундамент для понимания реализации потоков в конкретных ОС.

Исторически первая модель. Быстрая, но уязвимая — один блокирующий вызов останавливает всё. Спросите аудиторию: в каких случаях это приемлемо?

Модель Linux и Windows сегодня. Настоящий параллелизм на многоядерных системах, но за это приходится платить расходом ресурсов и ограничением числа потоков.

Компромиссная модель — сложна в реализации, но гибка. На практике многие системы эволюционировали к модели «один к одному», отказавшись от этой модели.

Сводная таблица для сравнения. «Многие к одному» — по сути потоки уровня пользователя, «один к одному» — ядерные потоки. Запомните компромиссы каждой модели.

Проиллюстрируйте каждый пункт примером. Отзывчивость — UI не зависает. Экономичность — создание потока в 10–100 раз дешевле процесса.

pthread — стандартный API потоков в UNIX. Используем на практических занятиях. Запомните основные функции — понадобятся для лабораторных.

Пользовательские потоки — библиотека берёт на себя планирование, ядро ничего не знает. Быстро, но ограниченно: блокирующий вызов стопит весь процесс.

Главная проблема — блокирующие системные вызовы. Если один поток вызывает read(), весь процесс ждёт. Обёртки и неблокирующий I/O — обходные пути.

Ядро управляет потоками напрямую — блокировка одного не мешает другим. Но каждое переключение — системный вызов, а это накладные расходы.

Наглядное сравнение двух подходов. Пользовательские — быстрые, но ограниченные. Ядерные — полноценные, но с накладными расходами на системные вызовы.

Попытка получить лучшее от обоих миров. Исторически интересна, но большинство современных ОС выбрали модель «один к одному».

Уникальная особенность Linux — единый вызов для создания и процессов, и потоков. Разница только в флагах. Элегантное архитектурное решение.

fork() — тяжёлый, clone() — гибкий. Подчеркните: pthread_create в Linux внутри использует clone() с флагом CLONE_VM.

В Linux нет отдельного понятия «поток» — всё задачи. Унифицированная модель. PID и tid — разные вещи, что иногда путает начинающих.

Переходим ко второй большой теме. IPC — фундамент для микросервисов, клиент-серверных приложений, конвейеров оболочки.

Два класса механизмов. Передача данных — данные копируются. Разделяемые ресурсы — процессы работают с одной памятью напрямую.

Важное различие: каналы дают и коммуникацию, и синхронизацию. Семафоры — только синхронизацию. Выбор механизма зависит от задачи.

Два стандарта IPC. System V — старше, POSIX — современнее и удобнее. На практике стоит предпочитать POSIX, но System V всё ещё встречается в legacy-коде.

Каналы — простейший IPC. Shell-конвейер `cmd1 | cmd2` — это pipe. Ограничение: только между родственными процессами (после fork).

Разберите код построчно. Обратите внимание: оба конца pipe нужно закрывать в каждом процессе — частая ошибка студентов.

FIFO решает главное ограничение pipe — работает между любыми процессами через имя в файловой системе. Но по-прежнему однонаправленный.

Очереди сообщений дают структурированный обмен — каждое сообщение имеет тип. Процесс может выбирать, какие сообщения читать, что отличает их от каналов.

Самый быстрый IPC — нет копирования данных. Но требуется ручная синхронизация — тема следующей лекции. Подчеркните этот ключевой компромисс.

Простой пример: создаём сегмент, подключаем к адресу, работаем как с обычной памятью. В реальном коде необходима синхронизация через семафоры.

mmap — альтернатива System V shm. Отображает файл в память: даёт и IPC, и работу с файлами. Часто предпочтительнее shmget/shmat.

Семафоры — механизм синхронизации, а не передачи данных. Операции P и V — атомарны. Подробно разберём в следующей лекции 07.

Сигналы — простейший и самый ограниченный механизм. Полезны для уведомлений, но не для передачи данных. SIGUSR1/SIGUSR2 — для пользовательских нужд.

Сокеты — самый универсальный механизм IPC. Работают и локально, и по сети. Unix domain sockets — для быстрой локальной IPC без сетевого оверхеда.

Практический пример создания двух потоков. Обратите внимание: pthread_join обязателен — без него main завершится раньше потоков.

Классический паттерн — встречается повсюду: буфер клавиатуры, очереди печати, message brokers. Ключевая сложность — синхронизация буфера.

Thread pool — стандартный паттерн в серверных приложениях. Веб-серверы, СУБД используют пулы потоков для предсказуемой производительности.

Fork-Join — паттерн для параллельных вычислений. Java ForkJoinPool, OpenMP — примеры реализации. Полезен для делимых на независимые подзадачи.

Итоговая таблица для выбора механизма IPC. Максимальная скорость — разделяемая память, простота — каналы, универсальность — сокеты.

Переход к итогам лекции. Сделайте паузу и спросите, есть ли вопросы, прежде чем перейти к ключевым выводам.

Главные тезисы лекции. clone() и IPC — два столпа, на которых строится понимание процессов и потоков в Linux.

Эти вопросы — основа для подготовки к экзамену. Рекомендуйте студентам попытаться ответить на каждый без конспекта.

Таненбаум — основной учебник, глава 2. Стивенс — глубокое погружение в IPC. Kerrisk — лучший справочник по системному программированию Linux.